package final_wearebatman_model;

import final_wearebatman_view.CircuitView;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map;
import java.util.StringTokenizer;


//a circuit osztály valósítja meg az áramkör központi logikáját, irányítja a működést
public class Circuit {

    protected LinkedList<Ioperable> gatelist; //láncolt lista az elemeknek
    protected LinkedList<Ioperable> sourcelist;//láncolt lista a jelforrásoknak
    protected boolean startedSimulation;
    protected Map table;
    private CircuitView circuitview;
    private Timer timer; //időzítő osztály meghívása
    private Thread timerThread; //külön szálban fut az időzítő

    //konstruktor
    public Circuit(String filename, CircuitView cv) {
        this.sourcelist = new LinkedList<Ioperable>();
        this.gatelist = new LinkedList<Ioperable>();
        this.startedSimulation = true;
        this.circuitview = cv;
        this.timer = new Timer(this);
        this.init(filename);
    }

    //fájl megnyitása, minden lista alaphelyzetbe állítása
    public void openFile(String filename) {
        this.gatelist.clear();
        this.sourcelist.clear();
        this.circuitview.clear();
        this.init(filename);
        circuitview.canvasRepaint();
    }

    //szimuláció indítása
    public void startSimulation() {
        if (timerThread != null && timerThread.isAlive()) {
            timerThread.interrupt();
        }
        this.timerThread = new Thread(timer);
        this.timerThread.setDaemon(true);
        this.timerThread.start();
    }

    //szimuláció leállítása
    public void stopSimulation() {
        if (timerThread.isAlive()) {
            timerThread.interrupt();
        }
    }

    //újrarajzolás
    public void requestRepaint() {
        if (this.circuitview != null) {
            this.circuitview.canvasRepaint();
        }
    }

    //számlálók nullázása
    public void resetCounters() {
        for (int i = 0; i < this.gatelist.size(); i++) {
            this.gatelist.get(i).resetCounter();
        }
    }

    //áramkör léptetése
    public void tick(int db) {
        for (int i = 1; i <= db; i++) {
            this.resetCounters();
            for (int j = 0; j < this.sourcelist.size(); j++) {
                this.sourcelist.get(j).operate();
            }
        }
        if (this.circuitview != null) {
            this.circuitview.canvasRepaint();
        }
    }

    //fájl beolvasása
    protected void init(String filename) {
        BufferedReader be = null;
        try {
            be = new BufferedReader(new FileReader(new File("tests\\" + filename)));
        } catch (FileNotFoundException ex) {
            System.out.println("FileNotFound");
            return;
        }

        StringBuilder content = new StringBuilder();
        try {
            String s = null;
            while ((s = be.readLine()) != null) {
                content.append(s + "\n");
            }
        } catch (Exception e) {
            System.out.println("FileReadError");
        }
       
        LinkedList<String> commands = new LinkedList<String>();
        StringTokenizer st = new StringTokenizer(content.toString(), "\n");

        while (st.hasMoreTokens()) {
            commands.add(st.nextToken());
        }

        ListIterator li = commands.listIterator();

        table = new HashMap();
        int tmp = 0;

        while (li.hasNext()) {
            st = new StringTokenizer(li.next().toString(), " ");
            String command = st.nextToken();
            String param1 = st.nextToken();
            String param2 = st.nextToken();
            String param3 = null;
            String param4 = null;
            String param5 = null;
            if (st.hasMoreTokens()) {
                param3 = st.nextToken();
            }
            if (st.hasMoreTokens()) {
                param4 = st.nextToken();
            }
            if (st.hasMoreTokens()) {
                param5 = st.nextToken();
            }

            //új elemek létrehozása
            if (command.equals("new")) {
                //generator
                if (param1.equals("Generator")) {
                    Generator gen = new Generator(param2);
                    this.sourcelist.add(gen);
                    if (this.circuitview != null) {
                        this.circuitview.createGeneratorView(gen, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "S" + (this.sourcelist.size() - 1));
                }
                //kapcsoló
                if (param1.equals("Switch")) {
                    Switch sw = new Switch(param2);
                    this.sourcelist.add(sw);
                    if (this.circuitview != null) {
                        this.circuitview.createSwitchView(sw, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "S" + (this.sourcelist.size() - 1));
                }
                //vezeték
                if (param1.equals("Wire")) {
                    Wire w = new Wire(param2);
                    this.gatelist.add(w);
                    if (this.circuitview != null) {
                        this.circuitview.createWireView(w, param2);
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
                //inverter
                if (param1.equals("Inverter")) {
                    Inverter inv = new Inverter(param2);
                    this.gatelist.add(inv);
                    if (this.circuitview != null) {
                        this.circuitview.createInverterView(inv, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
                //led
                if (param1.equals("Led")) {
                    Led l = new Led(param2);
                    this.gatelist.add(l);
                    if (this.circuitview != null) {
                        this.circuitview.createLedView(l, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
                //és kapu
                if (param1.equals("AND_Gate")) {
                    AND_Gate ag = new AND_Gate(param2);
                    this.gatelist.add(ag);
                    if (this.circuitview != null) {
                        this.circuitview.createAND_GateView(ag, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
                //vagy kapu
                if (param1.equals("OR_Gate")) {
                    OR_Gate og = new OR_Gate(param2);
                    this.gatelist.add(og);
                    if (this.circuitview != null) {
                        this.circuitview.createOR_GateView(og, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
                //oszcilloszkóp
                if (param1.equals("Scope")) {
                    Scope sc = new Scope(param2);
                    this.gatelist.add(sc);
                    if (this.circuitview != null) {
                        this.circuitview.createScopeView(sc, param2, Integer.parseInt(param3), Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
                //kompozit elem
                if (param1.equals("Composite")) {
                    Composite c = new Composite(param2, param3);
                    this.gatelist.add(c);
                    if (this.circuitview != null) {
                        this.circuitview.createCompositeView(c, param2, param3, Integer.parseInt(param4), Integer.parseInt(param5));
                    }
                    this.table.put(param2, "G" + (this.gatelist.size() - 1));
                }
            }

            //elemek öszekötése
            if (command.equals("connect")) {
                if (tmp++ == 0) {
                    System.out.println();
                }

                String id = table.get(param1).toString();
                String p2 = table.get(param2).toString();
                String p3 = param3;
                String p4 = table.get(param4).toString();
                String p5 = param5;

                boolean p2w = false;

                Object par2 = null;
                if (p2.charAt(0) == 'G') {
                    try {
                        par2 = (IhasOutput) this.gatelist.get(Integer.parseInt(p2.substring(1).toString()));
                        p2w = false;
                    } catch (ClassCastException e) {
                        par2 = (Wire) this.gatelist.get(Integer.parseInt(p2.substring(1).toString()));
                        p2w = true;
                    }
                }
                if (p2.charAt(0) == 'S') {
                    par2 = (IhasOutput) this.sourcelist.get(Integer.parseInt(p2.substring(1).toString()));
                }

                IhasInput par4 = null;
                if (p4.charAt(0) == 'G') {
                    par4 = (IhasInput) this.gatelist.get(Integer.parseInt(p4.substring(1).toString()));
                }
                if (p4.charAt(0) == 'S') {
                    par4 = (IhasInput) this.sourcelist.get(Integer.parseInt(p4.substring(1).toString()));
                }

                if (p2w) {
                    ((Wire) this.gatelist.get(Integer.parseInt(id.substring(1).toString()))).connect((Wire) par2, par4, Integer.parseInt(p5.toString()));
                    if (this.circuitview != null) {
                        circuitview.connectWire(param1, param2, Integer.parseInt(p3), param4, Integer.parseInt(param5));
                    }

                } else {
                    ((Wire) this.gatelist.get(Integer.parseInt(id.substring(1).toString()))).connect((IhasOutput) par2, Integer.parseInt(p3.toString()), par4, Integer.parseInt(p5.toString()));
                    if (this.circuitview != null) {
                        circuitview.connectWire(param1, param2, Integer.parseInt(p3), param4, Integer.parseInt(param5));
                    }
                }

            }
        }

    }

    //generátorok stringjének beállítása
    public void setGenerator(String name, String data) {
        try {
            String s = table.get(name).toString();
            Generator gen = (Generator) this.sourcelist.get(Integer.parseInt(s.substring(1).toString()));
            if (data.matches("[01]+")) {
                gen.setData(data);
            } else {
                System.out.println("BadState");
            }
        } catch (Exception e) {
            System.out.println("NameNotFound");
        }
    }
}
